package com.baizhi.cmfz.service.impl;

import com.baizhi.cmfz.annotation.AddCacheAnnotation;
import com.baizhi.cmfz.service.UserService;
import com.baizhi.cmfz.service.UserThreadService;
import com.baizhi.cmfz.util.ThreadPollUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
@Service
public class UserThreadServiceImpl implements UserThreadService {
    @Autowired
    private UserService userService;
    private Logger logger = LoggerFactory.getLogger(UserThreadServiceImpl.class);

    /**
     * 三个方法串行执行
     * @return
     */
    @Override
    public Map selectUserSerial() {
        long startTime = System.currentTimeMillis();
        Map map = new HashMap();
        List<Map> maps = userService.selectSex();
        Map map1 = userService.selectprovince();
        Map map2 = userService.selectDate();
        map.put("sex",maps);
        map.put("province",map1);
        map.put("date",map2);
        long endTime = System.currentTimeMillis();
        //log.info(String.valueOf((endTime-startTime)));
        logger.debug(String.valueOf((endTime-startTime)));
        return map;
    }

    /**
     *使用多线程执行代码 需要解决两个问题
     * 1、线程的创建：使用线程池工具类进行创建线程，添加任务
     * 2、多线程并发时，主线程不会等待子线程，需要解决主线程的等待问题
     *      在解决线程的等待问题的时候有多种方式：
     *      ① 使用future方法，这个方法的的返回值是线程执行的结果 可用于判断线程是否执行完毕
     *      ② 常用的方法是使用countDownLatch并发包，这是一个线程计数器，在创建线程对象时
     *      可以设定线程的任务数量，在线程中执行方法计数器-1 await方法让主线程等待
     *      当计数器变为0时主线程继续
     * @return
     */
    @Override
    @AddCacheAnnotation
    @Transactional(readOnly = true)
    public Map selectUserParallel() throws InterruptedException {
        long startTime = System.currentTimeMillis();
        Map map = new HashMap();
        //创建线程
        ThreadPoolExecutor executor = ThreadPollUtil.executor;
        //设置线程的任务为3 也就是计数器为3，
        //执行完一个线程-1 当计数器为0 时，主线程结束等待
        CountDownLatch countDownLatch = new CountDownLatch(3);
        executor.submit(new Runnable() {
            @Override
            public void run() {
                List<Map> maps = userService.selectSex();
                map.put("sex",maps);
                countDownLatch.countDown();
            }
        });
        executor.submit(new Runnable() {
            @Override
            public void run() {
                Map map1 = userService.selectprovince();
                map.put("province",map1);
                countDownLatch.countDown();
            }
        });
        executor.submit(new Runnable() {
            @Override
            public void run() {
                Map map2 = userService.selectDate();
                map.put("date",map2);
                countDownLatch.countDown();
            }
        });
        countDownLatch.await();
        long endTime = System.currentTimeMillis();
        log.info(String.valueOf((endTime-startTime)));
        logger.debug(String.valueOf((endTime-startTime)));
        logger.debug(String.valueOf((endTime-startTime)));
        return map;
    }
}
